//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Copyright (C) LibG.org. 2008. All rights reserved.                       //
//                                                                          //
// Licensed under GPL, you may use this file except for commercial purpose. //
//                                                                          //
// Permission to use, copy, modify, and distribute this software in object  //
// code form for any purpose and without fee is hereby granted, provided    //
// that the above copyright notice appears in all copies and that both that //
// copyright notice and the limited warranty and restricted rights notice   //
// below appear in all supporting documentation.                            //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#ifndef HEADER_GIFLOAT_H
#define HEADER_GIFLOAT_H

#define EPSILON_FLOAT   1e-6f       // loose tolerance ( 1.1929093e-7 )
#define EPSILON_DOUBLE  1e-12       // loose tolerance ( 2.220446049250313e-16 )

template<typename T1, typename T2>
class giReal
{
private:
    // value
    T1 mValue;

public:
    // constructors and destructor
    inline giReal() { mValue = 0.0f; }
    inline giReal( const T1& v ) { mValue = v; }
    inline giReal( const giReal& v ) { mValue = v.mValue; }
    inline ~giReal() {}

    // implicit conversion
    inline operator T1() const { return mValue; }
    inline operator T2() const { return (T2)mValue; }
    inline operator int() const { return (int)( mValue + (T1)0.5 ); }
    inline operator long() const { return (long)( mValue + (T1)0.5 ); }

    // assignment operators
    inline giReal& operator= ( const T1& v ) { mValue = v; return *this; }
    inline giReal& operator= ( const giReal& v ) { mValue = v.mValue; return *this; }
    inline T1& operator+= ( const T1& v ) { mValue += v; return mValue; }
    inline T1& operator-= ( const T1& v ) { mValue -= v; return mValue; }
    inline T1& operator*= ( const T1& v ) { mValue *= v; return mValue; }
    inline T1& operator/= ( const T1& v ) { mValue /= v; return mValue; }

    // relational and equality / control flow
    inline bool operator== ( const T1& v ) const { register T1 x = mValue - v; return -kEpsilon < x && x < kEpsilon; }
    inline bool operator!= ( const T1& v ) const { register T1 x = mValue - v; return x >= kEpsilon || x <= -kEpsilon; }
    inline bool operator> ( const T1& v ) const { return mValue > v && *this != v; }
    inline bool operator>= ( const T1& v ) const { return mValue > v || *this == v; }
    inline bool operator< ( const T1& v ) const { return mValue < v && *this != v; }
    inline bool operator<= ( const T1& v ) const { return mValue < v || *this == v; }

    // arithmetic operators
    inline T1 operator+ ( const T1& v ) const { return mValue + v; }
    inline T1 operator- ( const T1& v ) const { return mValue - v; }
    inline T1 operator* ( const T1& v ) const { return mValue * v; }
    inline T1 operator/ ( const T1& v ) const { return mValue / v; }

    // unary operators
    inline giReal operator- () const { return -mValue; }
    inline giReal operator+ () const { return mValue; }

    // prefix
    inline giReal& operator++ () { ++mValue; return *this; }
    inline giReal& operator-- () { --mValue; return *this; }

    // postfix
    inline giReal operator++ (int) { giReal t(*this); ++mValue; return t; }
    inline giReal operator-- (int) { giReal t(*this); --mValue; return t; }

    // tolerance
    static const T1 kEpsilon;
};

typedef giReal<float, double> giFloat;
const float giFloat::kEpsilon = EPSILON_FLOAT;

typedef giReal<double, float> giDouble;
const double giDouble::kEpsilon = EPSILON_DOUBLE;

#endif // HEADER_GIFLOAT_H